package base

import java.util.*
import java.util.logging.Logger

/**
 * Created by Darkness1m on 2017/5/25.
 */
//constructor声明为构造函数
// 直接跟在类名后的,是主构造函数
open class Person constructor(firstName:String){
    //主构造函数不能包含任何代码????存疑
    //初始化代码可以放到以init关键字为前缀的初始代码块中
    init {
        Logger.getGlobal().info("base.Person initialized with $firstName")
    }
    //次构造函数,返回值需要用this/super调用其他构造函数(被调用的构造函数最终必须调用主构造函数)
    constructor(firstName:String,age:Int):this(firstName){
    }
}
class Teacher public @SuppressWarnings constructor()
//如果没有任何注解或者是可见性修饰符,可以省略constructor这个关键字
class Student(name:String){
    val ccc = name.toUpperCase()
}
//私有构造函数
class Doc private constructor()

//注意：在 JVM 上，如果主构造函数的所有的参数都有默认值，编译器会生成 一个额外
//的无参构造函数，它将使用默认值。这使得 Kotlin 更易于使用像 Jackson 或者 JPA 这样
//的通过无参构造函数创建类的实例的库。
open class Lesson(a: String="默认值"){
    open val a = a
    override fun toString(): String {
        return "The value is $a"
    }
    constructor(a: String,time: Date) : this()//必须使用this/super,调用某个构造函数
}

class LessonA(a: String) : Lesson(){
    //使用final禁止子类再进行覆盖
    final override var a:String=""//var可以覆盖父类的val属性,反之不行
    init {
        this.a = a
    }
}
class LessonB(a: String) : Lesson(){
}
class Course : Lesson {//没有主构造函数
//    constructor(name: String) : this()//抛错
    constructor(name: String) : super()
    constructor(name: String,time: Date) : super(name,time)

}

/*
fun base.main(args: Array<String>) {
    println(base.LessonA("哈哈哈").toString())//哈哈哈
    println(base.LessonB("哈哈哈").toString())//默认值
}*/
//接口
//接口所有属性方法,默认为open
interface School{
    val count: Int
}

//下面两种方式效果相同
class School1(override val count: Int) : School
open class School2(a: Int) : School {//接口不能有括号,而类必须有括号
    override val count: Int=a
    open fun absMethod(){}
}

//抽象类
abstract class School3: School2(3){
    override abstract fun absMethod()
}

//匿名对象
var a: School3 = object : School3(){//格式为 object : base.School3
    override fun absMethod() {}
}

open class One(x: Int){
    public open val y: Int = x
}
interface Two
val three: One = object : One(1), Two {//继承匿名类
    override val y: Int = 1
}

fun innerClass(){
    var a=0
    var b=1
    var c=object : One(a){
        override val y: Int=b//访问外部变量,且变量不需要像Java一样为final的
        fun test(){b=2}//甚至可以修改b的值
    }
}

//单例模式对象(不能有构造函数!)
object Four{
    fun getFour(one: One){}
    val a: String = "1"
}

//对象可以有超类型:
object Five : One(1){
    override val y: Int
        get() = super.y
}
//注:对象不能在局部作用域(TODO: 不是很懂...)
fun part(){
    object {

    }
}


//类内部的对象声明可以用companion标记,作为伴生对象
//伴生对象,是这个类被加载时,被初始化的
class Six{
    companion object Seven{
        fun createNumber(number: Int): Int{
            return number
        }
        fun create(): Six = Six()
    }
//    companion object{}//一个类只允许存在一个companion
}
class Eight{
    companion object//同样也可以带有可见性修饰符
}

val six = Six.create()//这样来调用
val six2 = Six.create()//可以省略Seven
val eight = Eight//对于没有名字的companion而言,直接是Companion关键字


fun main8(args: Array<String>) {
    Four.getFour(One(1))//使用类名+方法名调用
    println(Four.a)
}

//扩展的作用域
open class D
class D1 : D()
open class C {
    open fun D.foo() {
        println("base.D.base.foo in base.C")
    }
    open fun D1.foo() {
        println("base.D1.base.foo in base.C")
    }
    fun caller(d: D) {
        d.foo() // 调用扩展函数
    }
}
class C1 : C() {
    override fun D.foo() {
        println("base.D.base.foo in base.C1")
    }
    override fun D1.foo() {
        println("base.D1.base.foo in base.C1")
    }
}

fun main11(args: Array<String>) {
    //都是看方法定义的入参的类型,然后调用该类型下的方法
    C().caller(D()) // 输出 "base.D.base.foo in base.C"
    C1().caller(D()) // 输出 "base.D.base.foo in base.C1" —— 分发接收者虚拟解析
    C().caller(D1()) // base.D.base.foo in base.C //看方法定义的入参的类型
}

//密封类(TODO:暂不清楚使用场景,据说是和枚举类相似但又更强大)
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when(expr){
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN//使用密封类,如果知道只剩这一种了,可以省略else
}


class Outer{
    private val bar: Int = 2
    //嵌套类//有点像静态内部类,但好像有点不一样
    class Nested{
//       fun base.foo() = bar//不能访问外部类的变量
        fun foo(){}
    }
    //内部类//内部类会带有外部类的引用
    inner class Inner{
        fun foo() = bar//可以访问外部类变量
    }
}

fun main12(args: Array<String>) {
    Outer.Nested().foo()
//    base.Outer.Inner()//无法这样调用
    Outer().Inner().foo()
}
enum class Direction{
    EAST,SOUTH,WEST,NORTH
    //每个枚举常量都有两个属性
    //val name: String//名称 和 val ordinal: Int//位置
}
enum class Color(val rgb: Int){
    RED(0XFF0000),//以逗号分隔
    GREEN(0X00FF00),
    BLUE(0X0000FF)
}
enum class ProtocolState{
    WAITING{
        override fun signal(): ProtocolState = TALKING//可以有匿名类
    },
    TALKING{
        override fun signal(): ProtocolState = WAITING
    };//这里有个分号
    abstract fun signal(): ProtocolState//可以定义抽象方法让枚举常量实现
}

fun main(args: Array<String>) {
    //base.ProtocolState.valueOf("呵呵")//java.lang.IllegalArgumentException: No enum constant base.ProtocolState.呵呵
    println(ProtocolState.valueOf("WAITING"))//返回name属性==>WAITING
    println(ProtocolState.values())//这个枚举对象
    println(enumValues<Direction>().joinToString { it.ordinal.toString()+":"+it.name })//0:EAST, 1:SOUTH, 2:WEST, 3:NORTH
}